package com.thero.core.chess;

import com.thero.core.command.cmd.KillPiece;
import com.thero.core.command.cmd.MovePiece;
import com.thero.core.command.cmd.PutPiece;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;

/**
 * Created by wusk on 2017/11/27.
 * 游戏房间，房间负责游戏消息的创建（考虑到房间和游戏逻辑距离最近，让房间来创建消息或许更合适）。
 */
public class Room {
    private static final Logger logger = LoggerFactory.getLogger(Room.class);

    private static int ROOM_ID = 100000000;
    private boolean kill;
    private int times;
    private int id;
    private int current;
    private Stage stage;
    private Chessboard board;
    private List<Message> queue;
    private Map<Integer, Player> players;

    public Room(Player black, Player white){
        this.kill = false;
        this.times = 0;
        this.id = newRoomId();
        this.current = black.getId();
        this.stage = Stage.put;
        this.queue = new ArrayList<>(4);
        this.players = new HashMap<>(2);
        this.players.put(black.getId(), black);
        this.players.put(white.getId(), white);
        this.board = new Chessboard();

        matchSuccess();
    }

    public int getId(){
        return this.id;
    }

    public Player getCurrent(){
        return players.get(this.current);
    }

    public Player getRival(){
        Player current = players.get(this.current);
        return players.get(current.getRival());
    }

    public List<Message> getMessages(){
        return this.queue;
    }

    public void put(PutPiece put){
        if(put.getPlayerId() != current){
            notTurn(put.getPlayerId());
            return;
        }
        if(!Stage.put.equals(stage)){
            wrongStage();
            return;
        }
        Player player = players.get(current);
        short location = put.getLocation();
        short result = board.put(location, player);
        if (0 == result) {
            //构造一个回复消息
            int check = threeCheck(location);
            if(check > 0){
                this.times = check;
                this.kill = true;
                putThree(location);
            }else {
                //回复一个落子成功的消息
                putSuccess(location);
            }
        }else {
            actionFail(result);
        }
    }

    public void kill(KillPiece kill){
        if(kill.getPlayerId() != current){
            notTurn(kill.getPlayerId());
            return;
        }
        if(!this.kill){
            wrongStage();
            return;
        }
        short location = kill.getLocation();
        Player player = players.get(current);
        Player rival = players.get(player.getRival());
        short result = board.kill(location, stage, rival);
        if(0 == result){
            if(Stage.put.equals(stage)){
                putKill(location);
            }else {
                moveKill(location);
            }
        }else {
            actionFail(result);
        }
    }

    public void move(MovePiece move){
    }

    /**
     * 检查玩家是否在这个房间
     * @param playerId 玩家id
     * @return true 在房间 false 不在
     */
    public boolean playerCheck(int playerId){
        return null != players.get(playerId);
    }

    /**
     * 检查是否成三
     * @param location 检查的位置
     * @return 成三的数量，取值 0， 1， 2
     */
    private int threeCheck(int location){
        Player player = players.get(current);
        return board.checkThree(location, player);
    }

    /**
     * 检查是否有棋子可以吃
     * @return 结果
     */
    private boolean killCheck(){
        Player player = players.get(current);
        Player rival = players.get(player.getRival());
        return board.canKill(rival);
    }

    /**
     * 构造匹配成功的消息放到消息队列
     */
    private void matchSuccess(){
        Player black = getCurrent();
        Player white = getRival();

        Message blackMessage = new Message((short)2500, black.getHome(), 10);
        blackMessage.writeInt(black.getId());
        blackMessage.writeInt(white.getId());//对手ID
        blackMessage.writeShort((short)1);//行动标记，1表示行动方
        queue.add(blackMessage);

        Message whiteMessage = new Message((short)2500, white.getHome(), 10);
        whiteMessage.writeInt(white.getId());
        whiteMessage.writeInt(black.getId());
        whiteMessage.writeShort((short)0);
        queue.add(whiteMessage);
    }

    /**
     * 回复一个没轮到你的消息
     * @param playerId 被回复的玩家
     */
    private void notTurn(int playerId){
        Player player = players.get(playerId);
        Message message = new Message((short) 6501, player.getHome(), 4);
        message.writeInt(player.getId());
        queue.add(message);
    }

    private void wrongStage(){
        Player player = getCurrent();
        Message message = new Message((short) 6502, player.getHome(), 6);
        message.writeInt(player.getId());
        if(this.kill){
            message.writeShort((short)3);
        }else if(Stage.put.equals(stage)){
            message.writeShort((short)1);
        }else {
            message.writeShort((short)2);
        }
        queue.add(message);
    }

    /**
     * 创建行动失败的消息
     * @param code 失败信息编码
     */
    private void actionFail(short code){
        Player player = getCurrent();
        Message message = new Message(code, player.getHome(), 4);
        message.writeInt(player.getId());
        queue.add(message);
    }

    /**
     * 回复两条消息，行动方回复行动成功，并让出行动机会，回复对手
     * @param location 放子位置
     */
    private void putSuccess(short location){
        Player self = getCurrent();
        Message black = new Message((short)3500, self.getHome(), 8);
        black.writeInt(self.getId());
        black.writeShort(location);
        black.writeShort((short)0);
        queue.add(black);

        Player rival = getRival();
        Message white = new Message((short)3500, rival.getHome(), 10);
        white.writeInt(rival.getId());
        white.writeShort(location);
        white.writeShort((short)1);
        white.writeShort(nextAction(self, rival));
        queue.add(white);
        this.current = rival.getId();
    }

    private void moveSuccess(short source, short target){
        Player self = getCurrent();
        Message black = new Message((short)3500, self.getHome(), 8);
        black.writeInt(self.getId());
        black.writeShort(source);
        black.writeShort(target);
        black.writeShort((short)0);
        queue.add(black);

        Player rival = getRival();
        Message white = new Message((short)3500, rival.getHome(), 10);
        white.writeInt(rival.getId());
        black.writeShort(source);
        black.writeShort(target);
        white.writeShort((short)1);
        white.writeShort(nextAction(self, rival));
        queue.add(white);
        this.current = rival.getId();
    }

    /**
     * 吃子成功，落子阶段吃子
     * @param location 吃子位置
     */
    public void putKill(short location){
        this.times = times - 1;
        if(0 == times){
            this.kill = false;
            killFinish(location, (short) 5500);
        }else {
            if(!killCheck()){
                killFinish(location, (short) 5601);
            }else {
                Player self = getCurrent();
                Message black = new Message((short)5600, self.getHome(), 10);
                black.writeInt(self.getId());
                black.writeShort(location);
                black.writeShort((short)1);
                black.writeShort((short)3);
                queue.add(black);

                Player rival = getRival();
                Message white = new Message((short)5600, rival.getHome(), 8);
                white.writeInt(rival.getId());
                white.writeShort(location);
                white.writeShort((short)0);
                queue.add(white);
                this.current = rival.getId();
            }
        }
    }

    private void moveKill(short location){
        this.kill = false;
        Player rival = this.getRival();
        int count = board.pieceCount(rival);
        if(count < 3){//当前玩家赢了
            Player self = getCurrent();
            Message black = new Message((short) 6600, self.getHome(), 8);
            black.writeInt(self.getId());
            black.writeShort(location);
            black.writeShort((short)1);
            queue.add(black);

            Message white = new Message((short) 6600, rival.getHome(), 8);
            white.writeInt(rival.getId());
            white.writeShort(location);
            white.writeShort((short)0);
            queue.add(white);
        }else {
            killFinish(location, (short) 5500);
        }
    }

    private void killFinish(short location, short code){
        this.kill = false;
        this.times = 0;
        Player self = getCurrent();
        Message black = new Message(code, self.getHome(), 8);
        black.writeInt(self.getId());
        black.writeShort(location);
        black.writeShort((short)0);
        queue.add(black);

        Player rival = getRival();
        Message white = new Message(code, rival.getHome(), 10);
        white.writeInt(rival.getId());
        white.writeShort(location);
        white.writeShort((short)1);
        white.writeShort(nextAction(self, rival));
        queue.add(white);
        this.current = rival.getId();
    }

    private short nextAction(Player self, Player rival){
        if(!rival.havePieces()){
            if(!self.havePieces()){
                //转阶段，清除不可用标记
                this.stage = Stage.move;
                this.board.allValid();
            }
            return (short)2;
        }else {
            return (short)1;
        }
    }

    /**
     * 落子阶段成三
     * @param location 落子位置
     */
    private void putThree(short location){
        boolean check = killCheck();
        if(check){
            Player self = getCurrent();
            Message black = new Message((short)3600, self.getHome(), 10);
            black.writeInt(self.getId());
            black.writeShort(location);
            black.writeShort((short)1);
            black.writeShort((short)3);
            queue.add(black);

            Player rival = getRival();
            Message white = new Message((short)3600, rival.getHome(), 8);
            white.writeInt(rival.getId());
            white.writeShort(location);
            white.writeShort((short)0);
            queue.add(white);
        }else {
            putSuccess(location);
        }
    }

    /**
     * 走棋阶段成三
     * @param source 起始位置
     * @param target 终点位置
     */
    private void moveThree(short source, short target){
        boolean check = killCheck();
        if(check){
            Player self = getCurrent();
            Message black = new Message((short)4600, self.getHome(), 12);
            black.writeInt(self.getId());
            black.writeShort(source);
            black.writeShort(target);
            black.writeShort((short)1);
            black.writeShort((short)3);
            queue.add(black);

            Player rival = getRival();
            Message white = new Message((short)4600, rival.getHome(), 10);
            white.writeInt(rival.getId());
            white.writeShort(source);
            black.writeShort(target);
            white.writeShort((short)0);
            queue.add(white);
        }else {
            moveSuccess(source, target);
        }
    }

    /**
     * 生成房间ID
     * @return id
     */
    private synchronized int newRoomId(){
        ROOM_ID = ROOM_ID + 1;
        if(ROOM_ID > 999999999){
            ROOM_ID = 100000000;
        }
        return ROOM_ID;
    }
}
